using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Maze;
using Nine;
using Nine.Components;
using Nine.Graphics;
using Nine.Graphics.Primitives;
using Nine.Graphics.ObjectModel;
using Nine.Navigation;

namespace EaWebMaze
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        //---def----
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        ModelBatch modelBatch;
        BasicEffect kockaEfekt;
        //----------
        //---ekran----
        private int BackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width - 100;
        private int BackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height - 100;
        //-----------

        //-----teren-----
        DrawableSurface terrain;
        RasterizerState wireframe;
        BasicEffect terrainEffect;
        //------------
        //----kamera----
        TopDownEditorCamera camera;
        Vector3 cameraPosition = new Vector3(62, -50, 71);
        float leftrightRot = 0.059f;
        float updownRot = 1.06f;
        const float rotationSpeed = 0.05f;
        const float moveSpeed = 40.0f;
        MouseState originalMouseState;
        Matrix viewMatrix;
        Matrix projectionMatrix;
        GraphicsDevice device;
        //-------------
        //sve vezano za lavirint
        private static MazeCreator _creator;
        public static byte[,] maze;
        int mazeSize = 23;
        Cube[,] mazeCube;
        //--------------

        

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            graphics.SynchronizeWithVerticalRetrace = false;
            graphics.PreferredBackBufferWidth = BackBufferWidth;
            graphics.PreferredBackBufferHeight = BackBufferHeight;
            IsMouseVisible = true;
            IsFixedTimeStep = false;
            Window.AllowUserResizing = true;
            graphics.PreferMultiSampling = true;
            graphics.ApplyChanges();
            base.Initialize();
        }

      
        protected override void LoadContent()
        {
           
            Components.Add(new InputComponent(Window.Handle));
            spriteBatch = new SpriteBatch(GraphicsDevice);
            camera = new TopDownEditorCamera(GraphicsDevice);
            modelBatch = new ModelBatch(GraphicsDevice);
            kockaEfekt = new BasicEffect(GraphicsDevice);
            kockaEfekt.TextureEnabled = true;
            kockaEfekt.Texture = Content.Load<Texture2D>("box");
            device = GraphicsDevice;
            terrain = new DrawableSurface(GraphicsDevice, Content.Load<Heightmap>("heightmap"), 32);
            terrainEffect = new BasicEffect(GraphicsDevice);
            terrain.LightingEnabled = true;
            terrainEffect.TextureEnabled = true;
            terrainEffect.Texture = Content.Load<Texture2D>("Mountain");
            terrainEffect.PreferPerPixelLighting = true;
            terrainEffect.AmbientLightColor = Vector3.One * 0.1f;
            terrainEffect.DirectionalLight0.DiffuseColor = Vector3.One * 0.1f;
            terrainEffect.DirectionalLight0.SpecularColor = Vector3.Zero;
            terrainEffect.DirectionalLight0.Direction = new Vector3(0, -0.707107f, -0.707107f);
            

            wireframe = new RasterizerState() { FillMode = FillMode.WireFrame, CullMode = CullMode.None };


            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.3f, 1000.0f);

            Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);
            originalMouseState = Mouse.GetState();

            //----lavirint---------
            _creator = new MazeCreator(mazeSize, mazeSize, new System.Drawing.Point(1, 1));
            maze = _creator.CreateMaze();


            mazeCube= new Cube[mazeSize,mazeSize];
            for (int i = 0; i < _creator.Height; i++)
                for (int j = 0; j < _creator.Width; j++)
                    mazeCube[i, j] = new Cube(GraphicsDevice, 5.0f);
            //---------------

            UpdateViewMatrix();
        
          
        }

       
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

         protected override void Update(GameTime gameTime)
        {
             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
  float timeDifference = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            ProcessInput(timeDifference);
            
            base.Update(gameTime);
        }

         protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

             //teren--------

            Vector3 eyePosition = Matrix.Invert(viewMatrix).Translation;
            terrain.UpdateLevelOfDetail(eyePosition);
            // Draw the terrain
            BoundingFrustum frustum = new BoundingFrustum(viewMatrix * projectionMatrix);


            modelBatch.Begin(ModelSortMode.Deferred, viewMatrix, projectionMatrix, BlendState.AlphaBlend, SamplerState.LinearWrap, null,
                Keyboard.GetState().IsKeyDown(Keys.Space) ? wireframe : null);
            {
                foreach (var patch in terrain.Patches)
                {
                    // Cull patches that are outside the view frustum
                    if (frustum.Contains(patch.BoundingBox) != ContainmentType.Disjoint)
                    {
                        modelBatch.DrawSurface(patch, terrainEffect);
                    }
                }
            }
            modelBatch.End();

             //-------------
            Matrix world = Matrix.Identity;
            float p=0;
             //-------maze drawing-------
            for (int j = 0; j < _creator.Height; j++)
            {

                for (int i = 0; i < _creator.Width; i++)
                {
                   
                 
                    if (maze[j, i] != 0)
                    {
                        float positionWorld = new float();
                        if (terrain.TryGetHeight(5*i+10, 5*j+10, out positionWorld))
                        {
                            p = positionWorld;
                        }
                        world = Matrix.CreateTranslation(5*i +10, 5*j+10, p+0.9f);
                        modelBatch.Begin(viewMatrix,projectionMatrix);
                        modelBatch.DrawPrimitive(mazeCube[i, j], world, kockaEfekt);
                        modelBatch.End();
                       
                    }
                }
            }

             //----------------
         
         

            base.Draw(gameTime);
        }
        //------------ pomeranje kamere----------

        private void ProcessInput(float amount)
        {
            KeyboardState keyState = Keyboard.GetState();
            MouseState currentMouseState = Mouse.GetState();
            if (keyState.IsKeyDown(Keys.LeftControl))
            {
                if (currentMouseState != originalMouseState)
                {
                    float xDifference = currentMouseState.X - originalMouseState.X;
                    float yDifference = currentMouseState.Y - originalMouseState.Y;
                    leftrightRot -= rotationSpeed * xDifference * amount;
                    updownRot -= rotationSpeed * yDifference * amount;
                    Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2);
                    UpdateViewMatrix();
                }
            }

            Vector3 moveVector = new Vector3(0, 0, 0);

            if (keyState.IsKeyDown(Keys.W) || keyState.IsKeyDown(Keys.Up))
                moveVector += new Vector3(0, 0, -1);
            if (keyState.IsKeyDown(Keys.Down) || keyState.IsKeyDown(Keys.S))
                moveVector += new Vector3(0, 0, 1);
            if (keyState.IsKeyDown(Keys.Right) || keyState.IsKeyDown(Keys.D))
                moveVector += new Vector3(1, 0, 0);
            if (keyState.IsKeyDown(Keys.Left) || keyState.IsKeyDown(Keys.A))
                moveVector += new Vector3(-1, 0, 0);
            if (keyState.IsKeyDown(Keys.Q))
                moveVector += new Vector3(0, 1, 0);
            if (keyState.IsKeyDown(Keys.Z))
                moveVector += new Vector3(0, -1, 0);
            AddToCameraPosition(moveVector * amount);
        }

        private void AddToCameraPosition(Vector3 vectorToAdd)
        {
            Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);
            Vector3 rotatedVector = Vector3.Transform(vectorToAdd, cameraRotation);
            cameraPosition += moveSpeed * rotatedVector;
            UpdateViewMatrix();
        }

        private void UpdateViewMatrix()
        {
            Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);

            Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
            Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);

            Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
            Vector3 cameraFinalTarget = cameraPosition + cameraRotatedTarget;

            Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);

            viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraFinalTarget, cameraRotatedUpVector);
        }

        //-------------------------------------------



    }

}
